﻿using System;
using System.Collections.Generic;
using System.IO;

namespace Ndns.Packet.ResourceRecords
{
    public sealed class DnsResourceRecordMX : DnsResourceRecord
    {

        /// <summary>
        /// 表示应答中的优先级记录。
        /// </summary>
        public ushort Preference { get; set; }

        /// <summary>
        /// 表示应答中的域名记录。
        /// </summary>
        public DnsHostName MXHostName { get; set; }

        public override DnsRecordType Type { get => DnsRecordType.MX; set => throw new NotSupportedException(); }


        /// <summary>
        /// 根据相关信息构造DnsResourceRecordMX实例。
        /// </summary>
        /// <param name="hostName">DNS应答的主机名信息。</param>
        /// <param name="c">DNS应答的类别。</param>
        /// <param name="ttl">DNS应答的超时时间。</param>
        /// <param name="mxHostName">DNS应答的数据。</param>
        public DnsResourceRecordMX(DnsHostName hostName, DnsClass c, uint ttl, ushort preferenceLevel, DnsHostName mxHostName)
            : base(hostName, c, ttl)
        {
            Preference = preferenceLevel;
            MXHostName = mxHostName ?? throw new ArgumentException(nameof(mxHostName));
        }


        /// <summary>
        /// 从包含数据包的流中以支持指针的方式构造实例。
        /// </summary>
        /// <param name="packetStream">数据包流，Position应该指向要解析的应答的开始。</param>
        /// <param name="offset">数据包的开始位置在流中的偏移量。</param>
        /// <returns>解析得到的实例。</returns>
        public static new DnsResourceRecordMX FromPacket(Stream packetStream, long packetStartIndex)
        {
            var hostName = DnsHostName.FromPacket(packetStream, packetStartIndex);
            var vType = packetStream.ReadNetworkUInt16();
            var vClass = packetStream.ReadNetworkUInt16();
            var vTTL = packetStream.ReadNetworkUInt32();
            int len = packetStream.ReadNetworkUInt16();
            PacketEndOfStreamException.CheckValue(vType, vClass, len);
            PacketEndOfStreamException.CheckValue(vTTL);

            if ((DnsRecordType)vType != DnsRecordType.MX)
                throw new FormatException();

            long pos = packetStream.Position;
            var vPreference = packetStream.ReadNetworkUInt16();
            PacketEndOfStreamException.CheckValue(vPreference);
            var vAnswer = DnsHostName.FromPacket(packetStream, packetStartIndex);
            packetStream.Seek(pos + len, SeekOrigin.Begin);

            return new DnsResourceRecordMX(hostName, (DnsClass)vClass, (uint)vTTL, (ushort)vPreference, vAnswer);
        }

        public override DnsResourceRecord Clone()
        {
            return new DnsResourceRecordMX(HostName, Class, TTL, Preference, MXHostName);
        }

        public override byte[] GetData()
        {
            using (var ms = new MemoryStream())
            {
                this.CopyDataTo(ms);
                return ms.ToArray();
            }
        }

        protected override int CopyDataTo(Stream s)
        {
            s.WriteNetworkUInt16(Preference);
            return 2 + MXHostName.CopyTo(s);
        }

        protected override int CopyCompressedDataTo(Stream s, Dictionary<string, DnsHostNamePointer> symbols, ref int offset)
        {
            s.WriteNetworkUInt16(Preference);
            offset += 2;
            return 2 + MXHostName.CopyCompressedTo(s, symbols, ref offset);
        }

        protected override int GetDataHashCode()
        {
            int total = 17;
            total = total * 37 + Preference.GetHashCode();
            total = total * 37 + MXHostName.GetHashCode();
            return total;
        }

        protected override bool TestDataEqualsTo(DnsResourceRecord other)
        {
            var record = other as DnsResourceRecordMX;
            if (record == null)
                return false;
            if (Preference != record.Preference)
                return false;
            return MXHostName.Equals(record.MXHostName);
        }
    }
}
